import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

// 测试代码
public class Main {

  public void run() {
    ParkingLot parkingLot = new ParkingLot(1, 1, 11);
    Car car = new Car();
    Bus bus = new Bus();
    boolean a1 = parkingLot.parkVehicle(new Motorcycle());
    boolean a2 = parkingLot.parkVehicle(new Car());
    boolean a3 = parkingLot.parkVehicle(new Car());
    boolean a4 = parkingLot.parkVehicle(new Car());
    boolean a5 = parkingLot.parkVehicle(new Car());
    boolean a6 = parkingLot.parkVehicle(car);
    boolean a7 = parkingLot.parkVehicle(bus);
    parkingLot.unParkVehicle(car);
    boolean a8 = parkingLot.parkVehicle(bus);
    System.out.println(a1);
    System.out.println(a2);
    System.out.println(a3);
    System.out.println(a4);
    System.out.println(a5);
    System.out.println(a6);
    System.out.println(a7);
    System.out.println(a8);
  }

  public static void main(String[] args) {
    Main parkingLotApp = new Main();
    parkingLotApp.run();
  }
}

// java版题解，粘贴以下代码到炼码中提交即可
// https://www.lintcode.com/problem/498/description
enum VehicleType {
  UNKNOWN(0),
  MOTORCYCLE(1),
  CAR(2),
  BUS(3);

  private int value;

  VehicleType(int value) {
    this.value = value;
  }

  public int getValue() {
    return value;
  }
}

abstract class Vehicle {

  protected VehicleType TYPE;
  protected int COST_SPOTS;
  protected Level atLevel;
  protected Set<Coordinate> atSpots;

  public Vehicle() {
    this.TYPE = VehicleType.UNKNOWN;
    this.COST_SPOTS = 0;
  }

  public abstract int[] getRange(int n);

  public void unpark() {
    if (this.atLevel != null) {
      for (Coordinate spot : this.atSpots) {
        this.atLevel.spots.remove(spot);
      }
      this.atLevel = null;
      this.atSpots = null;
    }
  }
}

class Motorcycle extends Vehicle {

  public Motorcycle() {
    this.TYPE = VehicleType.MOTORCYCLE;
    this.COST_SPOTS = 1;
  }

  @Override
  public int[] getRange(int n) {
    int[] range = new int[n];
    for (int i = 0; i < n; i++) {
      range[i] = i;
    }
    return range;
  }
}

class Car extends Vehicle {

  public Car() {
    this.TYPE = VehicleType.CAR;
    this.COST_SPOTS = 1;
  }

  @Override
  public int[] getRange(int n) {
    int start = n / 4;
    int[] range = new int[n - start];
    for (int i = 0; i < range.length; i++) {
      range[i] = start + i;
    }
    return range;
  }
}

class Bus extends Vehicle {

  public Bus() {
    this.TYPE = VehicleType.BUS;
    this.COST_SPOTS = 5;
  }

  @Override
  public int[] getRange(int n) {
    int start = n / 4 * 3;
    int[] range = new int[n - start];
    for (int i = 0; i < range.length; i++) {
      range[i] = start + i;
    }
    return range;
  }
}

class Level {

  private int id;
  private int m;
  private int n;
  protected Map<Coordinate, Vehicle> spots;

  public Level(int id, int m, int n) {
    this.id = id;
    this.m = m;
    this.n = n;
    this.spots = new HashMap<>();
  }

  public boolean parkVehicle(Vehicle vehicle) {
    int[] range = vehicle.getRange(this.n);
    for (int x = 0; x < this.m; x++) {
      int foundSpots = 0;
      Set<Coordinate> spots = new HashSet<>();
      for (int y : range) {
        if (this.spots.containsKey(new Coordinate(x, y))) {
          foundSpots = 0;
          spots.clear();
          continue;
        }

        foundSpots++;
        spots.add(new Coordinate(x, y));

        if (foundSpots == vehicle.COST_SPOTS) {
          vehicle.atLevel = this;
          vehicle.atSpots = spots;
          for (Coordinate spot : spots) {
            this.spots.put(spot, vehicle);
          }
          return true;
        }
      }
    }
    return false;
  }
}

class ParkingLot {

  private Level[] levels;

  public ParkingLot(int k, int m, int n) {
    this.levels = new Level[k];
    for (int i = 0; i < k; i++) {
      this.levels[i] = new Level(i, m, n);
    }
  }

  public boolean parkVehicle(Vehicle vehicle) {
    for (Level level : this.levels) {
      if (level.parkVehicle(vehicle)) {
        return true;
      }
    }
    return false;
  }

  public void unParkVehicle(Vehicle vehicle) {
    vehicle.unpark();
  }
}

class Coordinate {

  private int x;
  private int y;

  public Coordinate(int x, int y) {
    this.x = x;
    this.y = y;
  }

  @Override
  public boolean equals(Object o) {
    if (this == o) {
      return true;
    }
    if (o == null || getClass() != o.getClass()) {
      return false;
    }
    Coordinate that = (Coordinate) o;
    return x == that.x &&
        y == that.y;
  }

  @Override
  public int hashCode() {
    return 31 * x + y;
  }
}
